home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / MacTabbedPaneUI.java < prev    next >
Text File  |  1998-06-30  |  29KB  |  832 lines

  1. /*
  2.  * @(#)MacTabbedPaneUI.java    1.13 98/02/02
  3.  *
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  *
  19.  */
  20.  
  21.  
  22. package com.sun.java.swing.plaf.mac;
  23.  
  24. import java.awt.*;
  25. import java.awt.event.*;
  26. import com.sun.java.swing.*;
  27. import com.sun.java.swing.event.*;
  28. import com.sun.java.swing.plaf.*;
  29. import com.sun.java.swing.plaf.basic.BasicTabbedPaneUI;
  30. import java.io.Serializable; 
  31.  
  32. /**
  33.  * A Mac L&F implementation of TabbedPaneUI.
  34.  * <p>
  35.  * Warning: serialized objects of this class will not be compatible with
  36.  * future swing releases.  The current serialization support is appropriate
  37.  * for short term storage or RMI between Swing1.0 applications.  It will
  38.  * not be possible to load serialized Swing1.0 objects with future releases
  39.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  40.  * baseline for the serialized form of Swing objects.
  41.  *
  42.  * @version @(#)MacTabbedPaneUI.java    1.0 11/24/97
  43.  * @author Symantec
  44.  */
  45. public class MacTabbedPaneUI extends BasicTabbedPaneUI
  46. {
  47.  
  48. // Class constants
  49.  
  50.     static final int TAB_TOP_SEGMENT    = 0;
  51.     static final int TAB_MIDDLE_SEGMENT    = 1;
  52.     static final int TAB_BOTTOM_SEGMENT    = 2;
  53.     
  54.     static final int TAB_LEFT_SIDE        = 0;
  55.     static final int TAB_RIGHT_SIDE        = 1;
  56.     
  57.     static final int tabBorderSize[]    = { 5, 3, 4 };
  58.     static final int tabBorderY[]        = { 0, 5, 8 };
  59.     static final int tabBorderX[][]        =
  60.                                         {//    { TAB_LEFT_SIDE },    { TAB_RIGHT_SIDE }
  61.                                             {    3,                    8,    },        // { TAB_TOP_SEGMENT }
  62.                                             {    2,                    11    },        // { TAB_MIDDLE_SEGMENT }
  63.                                             {    0,                    12    }        // { TAB_BOTTOM_SEGMENT }
  64.                                         };
  65.  
  66.         // Content area constants
  67.     static final int TOP_BORDER_HEIGHT = 3;        // The part of the TAB_TOP_SEGMENT that is for the top border of the tab
  68.     static final int ROW_INDENT_SLOP = 6;        // Indent each row this much
  69.  
  70.  
  71.     private static final int ENABLED = 0;
  72.     private static final int DISABLED = 1;
  73.     private static final int FRONT = 2;
  74.     private static final int PRESSED = 3;
  75.  
  76.     private static final int TAB_BACKGROUND = 0;
  77.     private static final int TAB_FOREGROUND = 1;
  78.     private static final int TAB_HILITE1 = 2;
  79.     private static final int TAB_HILITE2 = 3;
  80.  
  81.     private static final int PANE_BACKGROUND = 0;
  82.     private static final int PANE_BORDER = 1;
  83.     private static final int PANE_BEVEL_HILITE1 = 2;
  84.     private static final int PANE_BEVEL_HILITE2 = 3;
  85.     private static final int PANE_BEVEL_SHADOW1 = 4;
  86.     private static final int PANE_BEVEL_SHADOW2 = 5;
  87.     private static final int PANE_BEVEL_ACCENT1 = 6;
  88.     private static final int PANE_BEVEL_ACCENT2 = 7;
  89.     private static final int PANE_BEVEL_ACCENT3 = 8;
  90.     
  91. // Class variables
  92.  
  93.     private static Insets contentBorderInsets = new Insets(3,3,3,3);
  94.     private static Color[][] tabColor = null;
  95.     private static Color[][] paneColor = null;
  96.     private static ImageIcon[] tabBorder = null;
  97.  
  98. // Instance variables
  99.  
  100.     protected int    numMidSegments;
  101.     protected int    mouseHiliteTab = -1;
  102.     protected int    paintingPaneState = ENABLED;
  103.     protected int    paintingTabState = ENABLED;
  104.  
  105.     protected MacTabbedPaneMouseGetter macTabbedPaneMouseGetter = new MacTabbedPaneMouseGetter();
  106.  
  107.     {
  108.         super.overlay = 6;
  109.     }
  110.  
  111. // UI creation
  112.  
  113.     public static ComponentUI createUI(JComponent tabbedPane) {
  114.         return new MacTabbedPaneUI();
  115.     }
  116.  
  117.  
  118. // UI Installation/De-installation
  119.  
  120.     public void installUI(JComponent container) {
  121.         super.installUI(container);
  122.  
  123.         container.removeMouseListener(super.mouseGetter);
  124.  
  125.         container.addMouseListener(macTabbedPaneMouseGetter);
  126.         container.addMouseMotionListener(macTabbedPaneMouseGetter);
  127.     }
  128.  
  129.     public void uninstallUI(JComponent container) {
  130.         super.uninstallUI(container);
  131.         container.removeMouseListener(macTabbedPaneMouseGetter);
  132.         container.removeMouseMotionListener(macTabbedPaneMouseGetter);
  133.     }
  134.  
  135.     protected void initPressedTabColors() {
  136.         tabColor[PRESSED][TAB_BACKGROUND] = UIManager.getColor("TabbedPane.pressedTabBackground");
  137.         tabColor[PRESSED][TAB_FOREGROUND] = UIManager.getColor("TabbedPane.pressedTabForeground");
  138.         tabColor[PRESSED][TAB_HILITE1] = UIManager.getColor("TabbedPane.pressedTabHilite1");
  139.         tabColor[PRESSED][TAB_HILITE2] = UIManager.getColor("TabbedPane.pressedTabHilite2");
  140.     }
  141.  
  142.     protected void initDisabledColors() {
  143.         tabColor[DISABLED][TAB_BACKGROUND] = UIManager.getColor("TabbedPane.disabledTabBackground");
  144.         tabColor[DISABLED][TAB_FOREGROUND] = UIManager.getColor("TabbedPane.disabledTabForeground");
  145.         tabColor[DISABLED][TAB_HILITE1] = UIManager.getColor("TabbedPane.disabledTabHilite1");
  146.         tabColor[DISABLED][TAB_HILITE2] = UIManager.getColor("TabbedPane.disabledTabHilite2");
  147.  
  148.         paneColor[DISABLED][PANE_BACKGROUND] = UIManager.getColor("TabbedPane.disabledPaneBackground");
  149.         paneColor[DISABLED][PANE_BORDER] = UIManager.getColor("TabbedPane.disabledPaneBorder");
  150.         paneColor[DISABLED][PANE_BEVEL_HILITE1] = UIManager.getColor("TabbedPane.disabledPaneBevelHilite1");
  151.         paneColor[DISABLED][PANE_BEVEL_HILITE2] = UIManager.getColor("TabbedPane.disabledPaneBevelHilite2");
  152.         paneColor[DISABLED][PANE_BEVEL_SHADOW1] = UIManager.getColor("TabbedPane.disabledPaneBevelShadow1");
  153.         paneColor[DISABLED][PANE_BEVEL_SHADOW2] = UIManager.getColor("TabbedPane.disabledPaneBevelShadow2");
  154.         paneColor[DISABLED][PANE_BEVEL_ACCENT1] = UIManager.getColor("TabbedPane.disabledPaneBevelAccent1");
  155.         paneColor[DISABLED][PANE_BEVEL_ACCENT2] = UIManager.getColor("TabbedPane.disabledPaneBevelAccent2");
  156.         
  157.         tabBorder[DISABLED] = (ImageIcon) UIManager.getIcon("TabbedPane.disabledTabBorder");
  158.     }
  159.  
  160.     protected void installDefaults(JComponent c) {
  161.         if (tabColor == null) {
  162.             tabColor = new Color[4][5];
  163.             tabColor[ENABLED][TAB_BACKGROUND] = UIManager.getColor("TabbedPane.enabledTabBackground");
  164.             tabColor[ENABLED][TAB_FOREGROUND] = UIManager.getColor("TabbedPane.enabledTabForeground");
  165.             tabColor[ENABLED][TAB_HILITE1] = UIManager.getColor("TabbedPane.enabledTabHilite1");
  166.             tabColor[ENABLED][TAB_HILITE2] = UIManager.getColor("TabbedPane.enabledTabHilite2");
  167.             tabColor[FRONT][TAB_BACKGROUND] = UIManager.getColor("TabbedPane.selectedTabBackground");
  168.             tabColor[FRONT][TAB_FOREGROUND] = UIManager.getColor("TabbedPane.selectedTabForeground");
  169.             tabColor[FRONT][TAB_HILITE1] = UIManager.getColor("TabbedPane.selectedTabHilite1");
  170.             tabColor[FRONT][TAB_HILITE2] = UIManager.getColor("TabbedPane.selectedTabHilite2");
  171.  
  172.             paneColor = new Color[2][9];
  173.             paneColor[ENABLED][PANE_BACKGROUND] = UIManager.getColor("TabbedPane.enabledPaneBackground");
  174.             paneColor[ENABLED][PANE_BORDER] = UIManager.getColor("TabbedPane.enabledPaneBorder");
  175.             paneColor[ENABLED][PANE_BEVEL_HILITE1] = UIManager.getColor("TabbedPane.enabledPaneBevelHilite1");
  176.             paneColor[ENABLED][PANE_BEVEL_HILITE2] = UIManager.getColor("TabbedPane.enabledPaneBevelHilite2");
  177.             paneColor[ENABLED][PANE_BEVEL_SHADOW1] = UIManager.getColor("TabbedPane.enabledPaneBevelShadow1");
  178.             paneColor[ENABLED][PANE_BEVEL_SHADOW2] = UIManager.getColor("TabbedPane.enabledPaneBevelShadow2");
  179.             paneColor[ENABLED][PANE_BEVEL_ACCENT1] = UIManager.getColor("TabbedPane.enabledPaneBevelAccent1");
  180.             paneColor[ENABLED][PANE_BEVEL_ACCENT2] = UIManager.getColor("TabbedPane.enabledPaneBevelAccent2");
  181.             paneColor[ENABLED][PANE_BEVEL_ACCENT3] = UIManager.getColor("TabbedPane.enabledPaneBevelAccent3");
  182.  
  183.             tabBorder = new ImageIcon[4];
  184.             tabBorder[ENABLED] = (ImageIcon) UIManager.getIcon("TabbedPane.enabledTabBorder");
  185.             tabBorder[FRONT] = (ImageIcon) UIManager.getIcon("TabbedPane.selectedTabBorder");
  186.             tabBorder[PRESSED] = (ImageIcon) UIManager.getIcon("TabbedPane.pressededTabBorder");
  187.          }
  188.     }
  189.  
  190. // UI Rendering
  191.  
  192.     public void paint(Graphics g, JComponent container) {
  193.         JTabbedPane pane = (JTabbedPane)container;
  194.         int selectedIndex = pane.getSelectedIndex();
  195.         int tabCount = pane.getTabCount();
  196.         if (tabCount != rects.length) {
  197.             calculateLayoutInfo(pane); 
  198.         }
  199.  
  200.         Rectangle bounds = pane.getBounds();
  201.         Insets insets = pane.getInsets();
  202.  
  203.         int height = bounds.height;
  204.         int width = bounds.width;
  205.         int tabHeight = totalTabHeight(pane,pane.getTabPlacement(), runCount);
  206.         Rectangle iconRect = new Rectangle(),
  207.                     textRect = new Rectangle();
  208.         Rectangle clipRect = g.getClipBounds();
  209.  
  210.         if (pane.isEnabled())
  211.         {
  212.             paintingPaneState = ENABLED;
  213.         }
  214.         else
  215.         {
  216.             if (tabColor[DISABLED][TAB_BACKGROUND] == null)
  217.                 initDisabledColors();
  218.             paintingPaneState = DISABLED;
  219.         }
  220.  
  221.         g.translate(insets.left, insets.top);
  222.  
  223.         // Paint runs of tabs from back to front
  224.         for (int i = runCount - 1; i >= 0; i--) {
  225.             int start = tabRuns[i];
  226.             int next = tabRuns[(i == runCount - 1)? 0 : i + 1];
  227.             int end = (next != 0? next - 1: tabCount - 1);
  228.             
  229.             // Paint a top border from the first tab to the right side
  230.             int rowBorderStart = rects[start].x - ROW_INDENT_SLOP - 1;
  231.             int rowBorderY = rects[start].y + rects[start].height;
  232.             paintTabRowBorder(g, rowBorderStart, rowBorderY, width - rowBorderStart);
  233.  
  234.             for (int j = start; j <= end; j++) {
  235.                 if (rects[j].intersects(clipRect)) {
  236.                     paintTab(g, pane, rects, j, iconRect, textRect);
  237.                 }
  238.             }
  239.         }
  240.  
  241.         paintContentBorderTop(g, selectedIndex, tabHeight, width);
  242.         paintContentBorderSidesAndBottom(g, 0, tabHeight, width, height - tabHeight);
  243.  
  244.         g.translate(-insets.left, -insets.top);
  245.     }
  246.  
  247.     protected void paintTab(Graphics g, JTabbedPane pane, Rectangle[] rects,
  248.                           int i, Rectangle iconRect, Rectangle textRect) {
  249.  
  250.         paintingTabState = paintingPaneState;
  251.         if (paintingTabState == ENABLED)
  252.         {
  253.             if (i == pane.getSelectedIndex())
  254.                 paintingTabState = FRONT;
  255.             else if (i == mouseHiliteTab)
  256.                 paintingTabState = PRESSED;
  257.         }
  258.             
  259.         Rectangle tabRect = rects[i];
  260.         int selectedIndex = pane.getSelectedIndex();
  261.         int tabPlacement  = pane.getTabPlacement();
  262.         boolean isSelected = selectedIndex == i;
  263.         
  264.         xNudge = calculateXNudge(pane,tabPlacement, i, isSelected); // broke these into separate function for easier subclassing.
  265.         yNudge = calculateYNudge(pane,tabPlacement, i, isSelected);
  266.         
  267.         paintTabBackground(g, pane, tabRect.x, tabRect.y, tabRect.width, tabRect.height, isSelected);
  268.         paintTabBorder(g, pane, tabRect.x, tabRect.y, tabRect.width, tabRect.height, isSelected);
  269.         
  270.         String title = pane.getTitleAt(i);
  271.         Font font = pane.getFont();
  272.         FontMetrics metrics = g.getFontMetrics(font);
  273.         Icon icon = pane.getIconAt(i);
  274.  
  275.         // hardwire tabPlacement=TOP until others supported
  276.         layoutLabel(TOP, metrics, title, icon, tabRect, iconRect, textRect, isSelected );
  277.         
  278.         paintText( g, pane, TOP, font, metrics, i, title, textRect, isSelected );
  279.         
  280.         paintIcon( g, pane, TOP, i, icon, iconRect, isSelected );
  281.         
  282.         paintFocusIndicator( g, pane, rects, i, iconRect, textRect );
  283.     }
  284.  
  285.     protected int calculateYNudge( Rectangle tabRect ) {
  286.         return 0;        // No nudge:  the selected tab displays at the same location as the others
  287.     }
  288.  
  289.     protected void paintTabRowBorder(Graphics g, int x, int y, int w) {
  290.         g.translate(x, y);
  291.  
  292.         g.setColor(paneColor[paintingPaneState][PANE_BORDER]);
  293.         g.drawLine(0, 0, w, 0);
  294.         g.setColor(paneColor[paintingPaneState][PANE_BEVEL_HILITE1]);
  295.         g.drawLine(0, 1, w, 1);
  296.         g.setColor(paneColor[paintingPaneState][PANE_BEVEL_HILITE2]);
  297.         g.drawLine(0, 2, w, 2);
  298.  
  299.         g.translate(-x, -y);
  300.     }
  301.  
  302.     protected void paintFocusIndicator(Graphics g, JTabbedPane pane, 
  303.                                         Rectangle[] rects, int i, 
  304.                                         Rectangle iconRect, Rectangle textRect) {}
  305.  
  306.     protected void paintContentBorderTop(Graphics g, int selectedIndex, int tabHeight, int width) {}
  307.  
  308.  
  309.     /** 
  310.       * This function draws the etch around the content area of the pane
  311.       * note: content area means the area below the tabs
  312.       */
  313.     protected void paintContentBorderSidesAndBottom(Graphics g, int x, int y, int w, int h) {
  314.         g.translate(x, y);
  315.         
  316.         h--;
  317.         w--;
  318.  
  319.         // Solid border
  320.         g.setColor(paneColor[paintingPaneState][PANE_BORDER]);
  321.         g.drawLine(0, 0, 0, h);            // Left
  322.         g.drawLine(w, 0, w, h);            // Right
  323.         g.drawLine(1, h, w - 1, h);        // Bottom
  324.  
  325.         // Left Bevel
  326.         g.setColor(paneColor[paintingPaneState][PANE_BEVEL_HILITE1]);
  327.         g.drawLine(1, 1, 1, h - 2);
  328.         g.setColor(paneColor[paintingPaneState][PANE_BEVEL_HILITE2]);
  329.         g.drawLine(2, 1, 2, h - 3);
  330.  
  331.         // Right Bevel
  332.         g.setColor(paneColor[paintingPaneState][PANE_BEVEL_ACCENT1]);
  333.         g.drawLine(w - 1, 1, w - 1, 1);
  334.         g.setColor(paneColor[paintingPaneState][PANE_BEVEL_SHADOW1]);
  335.         g.drawLine(w - 1, 2, w - 1, h - 1);
  336.  
  337.         g.setColor(paneColor[paintingPaneState][PANE_BEVEL_ACCENT2]);
  338.         g.drawLine(w - 2, 2, w - 2, 2);
  339.         g.setColor(paneColor[paintingPaneState][PANE_BEVEL_SHADOW2]);
  340.         g.drawLine(w - 2, 3, w - 2, h - 2);
  341.  
  342.         // Bottom Bevel
  343.         g.setColor(paneColor[paintingPaneState][PANE_BEVEL_ACCENT1]);
  344.         g.drawLine(1, h - 1, 1, h - 1);
  345.         g.setColor(paneColor[paintingPaneState][PANE_BEVEL_SHADOW1]);
  346.         g.drawLine(2, h - 1, w - 2, h - 1);
  347.  
  348.         g.setColor(paneColor[paintingPaneState][PANE_BEVEL_ACCENT2]);
  349.         g.drawLine(2, h - 2, 2, h - 2);
  350.         g.setColor(paneColor[paintingPaneState][PANE_BEVEL_SHADOW2]);
  351.         g.drawLine(3, h - 2, w - 3, h - 2);
  352.  
  353.         g.translate(-x, -y);
  354.     }
  355.  
  356.  
  357.         private void paintTabBorderPixel(Graphics g, Color hilitePixelColor, Color lolitePixelColor, int x, int y, int tabWidth)
  358.         {
  359.             g.setColor(hilitePixelColor);
  360.             g.drawLine(x, y, x, y);
  361.             if (lolitePixelColor != null) g.setColor(lolitePixelColor);
  362.             g.drawLine(tabWidth - x, y, tabWidth - x, y);        // Paint a mirror image
  363.         }
  364.  
  365.     /**
  366.       * this function draws the border around each tab
  367.       * note that this function does not draw the background of the tab.
  368.       * that is done elsewhere
  369.       */
  370.     protected void paintTabBorder(Graphics g, JTabbedPane pane, int x, int y, int w, int h, boolean isSelected) {
  371.         Image tabBorderImage = tabBorder[paintingTabState].getImage();
  372.         
  373.         g.translate(x, y);
  374.  
  375.         // Draw the TAB_TOP_SEGMENT border
  376.         int hIndent = getTopSegmentIndent();
  377.         g.drawImage(tabBorderImage,
  378.                     hIndent,                                                                        // dx1
  379.                     0,                                                                                // dy1
  380.                     hIndent + tabBorderSize[TAB_TOP_SEGMENT],                                        // dx2
  381.                     tabBorderSize[TAB_TOP_SEGMENT],                                                    // dy2
  382.                     tabBorderX[TAB_TOP_SEGMENT][TAB_LEFT_SIDE],                                        // sx1
  383.                     tabBorderY[TAB_TOP_SEGMENT],                                                    // sy1
  384.                     tabBorderX[TAB_TOP_SEGMENT][TAB_LEFT_SIDE] + tabBorderSize[TAB_TOP_SEGMENT],    // sx2
  385.                     tabBorderY[TAB_TOP_SEGMENT] + tabBorderSize[TAB_TOP_SEGMENT],                    // sy2
  386.                     pane);
  387.  
  388.         int dx1 = hIndent + tabBorderSize[TAB_TOP_SEGMENT];
  389.         int dx2 = w - (hIndent + tabBorderSize[TAB_TOP_SEGMENT]);
  390.         g.setColor(paneColor[paintingPaneState][PANE_BORDER]);
  391.         g.drawLine(dx1, 0, dx2, 0);
  392.  
  393.         g.setColor(tabColor[paintingTabState][TAB_HILITE1]);
  394.         g.drawLine(dx1, 1, dx2, 1);
  395.  
  396.         g.setColor(tabColor[paintingTabState][TAB_HILITE2]);
  397.         g.drawLine(dx1, 2, dx2, 2);
  398.  
  399.         g.drawImage(tabBorderImage,
  400.                     w - (hIndent + tabBorderSize[TAB_TOP_SEGMENT]),                                    // dx1
  401.                     0,                                                                                // dy1
  402.                     w - hIndent,                                                                    // dx2
  403.                     tabBorderSize[TAB_TOP_SEGMENT],                                                    // dy2
  404.                     tabBorderX[TAB_TOP_SEGMENT][TAB_RIGHT_SIDE],                                    // sx1
  405.                     tabBorderY[TAB_TOP_SEGMENT],                                                    // sy1
  406.                     tabBorderX[TAB_TOP_SEGMENT][TAB_RIGHT_SIDE] + tabBorderSize[TAB_TOP_SEGMENT],    // sx2
  407.                     tabBorderY[TAB_TOP_SEGMENT] + tabBorderSize[TAB_TOP_SEGMENT],                    // sy2
  408.                     pane);
  409.  
  410.         int vOffset = tabBorderSize[TAB_TOP_SEGMENT];
  411.         hIndent = tabBorderX[TAB_MIDDLE_SEGMENT][TAB_LEFT_SIDE] + numMidSegments;
  412.  
  413.  
  414.         // Draw the TAB_MIDDLE_SEGMENT borders
  415.         for (int midSegment = 0; midSegment < numMidSegments; midSegment++)
  416.         {
  417.             hIndent--;
  418.  
  419.             g.drawImage(tabBorderImage,
  420.                         hIndent,                                                                            // dx1
  421.                         vOffset,                                                                            // dy1
  422.                         hIndent + tabBorderSize[TAB_MIDDLE_SEGMENT],                                        // dx2
  423.                         vOffset + tabBorderSize[TAB_MIDDLE_SEGMENT],                                        // dy2
  424.                         tabBorderX[TAB_MIDDLE_SEGMENT][TAB_LEFT_SIDE],                                        // sx1
  425.                         tabBorderY[TAB_MIDDLE_SEGMENT],                                                        // sy1
  426.                         tabBorderX[TAB_MIDDLE_SEGMENT][TAB_LEFT_SIDE] + tabBorderSize[TAB_MIDDLE_SEGMENT],    // sx2
  427.                         tabBorderY[TAB_MIDDLE_SEGMENT] + tabBorderSize[TAB_MIDDLE_SEGMENT],                    // sy2
  428.                         pane);
  429.  
  430.             g.drawImage(tabBorderImage,
  431.                         w - (hIndent + tabBorderSize[TAB_MIDDLE_SEGMENT]),                                    // dx1
  432.                         vOffset,                                                                            // dy1
  433.                         w - hIndent,                                                                        // dx2
  434.                         vOffset + tabBorderSize[TAB_MIDDLE_SEGMENT],                                        // dy2
  435.                         tabBorderX[TAB_MIDDLE_SEGMENT][TAB_RIGHT_SIDE],                                        // sx1
  436.                         tabBorderY[TAB_MIDDLE_SEGMENT],                                                        // sy1
  437.                         tabBorderX[TAB_MIDDLE_SEGMENT][TAB_RIGHT_SIDE] + tabBorderSize[TAB_MIDDLE_SEGMENT],    // sx2
  438.                         tabBorderY[TAB_MIDDLE_SEGMENT] + tabBorderSize[TAB_MIDDLE_SEGMENT],                    // sy2
  439.                         pane);
  440.             
  441.             vOffset += tabBorderSize[TAB_MIDDLE_SEGMENT];
  442.         }
  443.  
  444.         // Draw BOTTOM SEGMENT border
  445.         g.drawImage(tabBorderImage,
  446.                     0,                                                                                    // dx1
  447.                     vOffset,                                                                            // dy1
  448.                     tabBorderSize[TAB_BOTTOM_SEGMENT],                                                    // dx2
  449.                     vOffset + tabBorderSize[TAB_BOTTOM_SEGMENT],                                        // dy2
  450.                     tabBorderX[TAB_BOTTOM_SEGMENT][TAB_LEFT_SIDE],                                        // sx1
  451.                     tabBorderY[TAB_BOTTOM_SEGMENT],                                                        // sy1
  452.                     tabBorderX[TAB_BOTTOM_SEGMENT][TAB_LEFT_SIDE] + tabBorderSize[TAB_BOTTOM_SEGMENT],    // sx2
  453.                     tabBorderY[TAB_BOTTOM_SEGMENT] + tabBorderSize[TAB_BOTTOM_SEGMENT],                    // sy2
  454.                     pane);
  455.  
  456.         g.drawImage(tabBorderImage,
  457.                     w - tabBorderSize[TAB_BOTTOM_SEGMENT],                                                // dx1
  458.                     vOffset,                                                                            // dy1
  459.                     w,                                                                                    // dx2
  460.                     vOffset + tabBorderSize[TAB_BOTTOM_SEGMENT],                                        // dy2
  461.                     tabBorderX[TAB_BOTTOM_SEGMENT][TAB_RIGHT_SIDE],                                        // sx1
  462.                     tabBorderY[TAB_BOTTOM_SEGMENT],                                                        // sy1
  463.                     tabBorderX[TAB_BOTTOM_SEGMENT][TAB_RIGHT_SIDE] + tabBorderSize[TAB_BOTTOM_SEGMENT],    // sx2
  464.                     tabBorderY[TAB_BOTTOM_SEGMENT] + tabBorderSize[TAB_BOTTOM_SEGMENT],                    // sy2
  465.                     pane);
  466.  
  467.         // Draw BOTTOM border
  468.         if (paintingTabState == FRONT)
  469.         {
  470.             vOffset += tabBorderSize[TAB_BOTTOM_SEGMENT];
  471.  
  472.             paintTabBorderPixel(g, paneColor[ENABLED][PANE_BORDER],            null,                                    0,    vOffset, w);
  473.             paintTabBorderPixel(g, paneColor[ENABLED][PANE_BEVEL_HILITE1],    paneColor[ENABLED][PANE_BEVEL_ACCENT3],    1,    vOffset, w);
  474.             paintTabBorderPixel(g, paneColor[ENABLED][PANE_BEVEL_HILITE2],    paneColor[ENABLED][PANE_BACKGROUND],    2,    vOffset, w);
  475.             g.setColor(tabColor[FRONT][TAB_BACKGROUND]);
  476.             g.drawLine(3, vOffset, w-3, vOffset);
  477.             vOffset++;
  478.  
  479.             paintTabBorderPixel(g, paneColor[ENABLED][PANE_BEVEL_HILITE1],    null,                                    0,    vOffset, w);
  480.             paintTabBorderPixel(g, paneColor[ENABLED][PANE_BEVEL_HILITE2],    paneColor[ENABLED][PANE_BEVEL_HILITE1],    1,    vOffset, w);
  481.             g.setColor(tabColor[FRONT][TAB_BACKGROUND]);
  482.             g.drawLine(2, vOffset, w-2, vOffset);
  483.             vOffset++;
  484.  
  485.             paintTabBorderPixel(g, paneColor[ENABLED][PANE_BEVEL_HILITE2],    null,                                    0,    vOffset, w);
  486.             g.setColor(tabColor[FRONT][TAB_BACKGROUND]);
  487.             g.drawLine(1, vOffset, w-1, vOffset);
  488.         }
  489.  
  490.         g.translate(-x, -y);
  491.     }
  492.  
  493.     protected void paintTabBackground(Graphics g, JTabbedPane pane, int x, int y, int w, int h, boolean isSelected) {
  494.         g.translate(x, y);
  495.  
  496.         g.setColor(tabColor[paintingTabState][TAB_BACKGROUND]);
  497.         
  498.         int hIndent, vOffset, segmentWidth;
  499.         
  500.         // Draw the TAB_TOP_SEGMENT background
  501.         hIndent = getTopSegmentIndent() + tabBorderSize[TAB_TOP_SEGMENT];
  502.         g.fillRect(hIndent, TOP_BORDER_HEIGHT,  w - (2 * hIndent) + 1, tabBorderSize[TAB_TOP_SEGMENT] - TOP_BORDER_HEIGHT);
  503.  
  504.         
  505.         // Draw the MIDDLE SEGMENT backgrounds
  506.         vOffset = tabBorderSize[TAB_TOP_SEGMENT];
  507.         hIndent = tabBorderX[TAB_MIDDLE_SEGMENT][TAB_LEFT_SIDE] + numMidSegments - 1 + tabBorderSize[TAB_MIDDLE_SEGMENT];
  508.         segmentWidth = w - (2 * hIndent) + 1;
  509.  
  510.         for (int midSegment = 0; midSegment < numMidSegments; midSegment++)
  511.         {
  512.             g.fillRect(hIndent, vOffset, segmentWidth, tabBorderSize[TAB_MIDDLE_SEGMENT]);
  513.             vOffset += tabBorderSize[TAB_MIDDLE_SEGMENT];
  514.             hIndent -= 1;
  515.             segmentWidth += 2;
  516.         }
  517.  
  518.  
  519.         // Draw BOTTOM SEGMENT background
  520.         g.fillRect(hIndent, vOffset, segmentWidth, tabBorderSize[TAB_BOTTOM_SEGMENT]);
  521.  
  522.         g.translate(-x, -y);
  523.     }
  524.  
  525.     protected void calculateLayoutInfo(JTabbedPane pane) {
  526.         Insets insets = pane.getInsets();
  527.         int paddingExemptRun = 0; 
  528.         maxTabHeight = maxTabHeight(pane); 
  529.         Font font = pane.getFont();
  530.         int maxX = pane.getSize().width - insets.right;
  531. //        int maxX = pane.getSize().width - (insets.right + 2);
  532.         int returnAt = maxX; 
  533.         int tabCount = pane.getTabCount();
  534.  
  535.         assureRectsCreated(tabCount);
  536.  
  537.         arrangeTabs(paddingExemptRun, maxTabHeight, overlay, font, 
  538.                     maxX, returnAt, tabCount, pane); 
  539.             
  540.         padSelectedTab(pane);
  541.     }
  542.  
  543.     protected void arrangeTabs(int paddingExemptRun, 
  544.                                 int maxTabHeight, int overlay, Font font, 
  545.                                 int maxX, int returnAt, int tabCount, 
  546.                                 JTabbedPane pane) {
  547.         FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(font);
  548.         Insets insets = pane.getInsets();        
  549.         int i, j;
  550.         int totalX = 0;
  551.         int h = insets.top;
  552.         int sRun = -1;
  553.         
  554.         runCount = 0;
  555.         
  556.         // Run through tabs and partition them into runs
  557.         for (i = 0; i < tabCount; i++) {
  558.             Rectangle rect = rects[i];
  559.             
  560.             if (i > 0) {
  561.                 rect.x = rects[i-1].x + rects[i-1].width;
  562.             } else {
  563.                 tabRuns[0] = 0;
  564.                 runCount = 1;
  565.                 rect.x = insets.left;
  566. //                rect.x = 2 + insets.left;
  567.             }
  568.             rect.width = tabWidth(pane, i, metrics);
  569.             
  570.             // Never move a TAB down a run if it is in the first column. 
  571.             // Even if there isn't enough room, moving it to a fresh 
  572.             // line won't help. 
  573.             //
  574.             if (rect.x != insets.left && rect.x + rect.width > returnAt) {
  575. //            if (rect.x != 2 + insets.left && rect.x + rect.width > returnAt) {
  576.                 if (runCount > tabRuns.length - 1) {
  577.                     expandTabRunsArray();
  578.                 }
  579.                 tabRuns[runCount] = i;
  580.                 runCount++;
  581.                 rect.x = insets.left;
  582. //                rect.x = 2 + insets.left;
  583.             }
  584.             rect.y = h;
  585.             rect.height = maxTabHeight;
  586. //            rect.y = h + selectedTabHeightPad;
  587. //            rect.height = maxTabHeight - 2;
  588.             if (i == pane.getSelectedIndex()) {
  589.                 sRun = runCount;
  590.             }
  591.         }
  592.         
  593.         // Rotate run array so that selected run is first
  594.         rotateTabRuns(pane,pane.getTabPlacement(),sRun);
  595.         
  596.         // Step through runs from back to front to calculate
  597.         // tab y locations and to pad runs appropriately
  598.         for (i = runCount - 1; i >= 0; i--) {
  599.             int start = tabRuns[i];
  600.             int next = tabRuns[i == (runCount - 1)? 0 : i + 1];
  601.             int end = (next != 0? next - 1 : tabCount - 1);
  602.             for (j = start; j <= end; j++) {
  603.                 Rectangle rect = rects[j];
  604.                 rect.y = h;
  605. //                rect.y = h + selectedTabHeightPad;
  606.                 rect.x += getRunIndent(i);
  607.             }
  608.             if (i != paddingExemptRun || runCount > 1) {
  609.                 padRun(start, end, maxX);
  610.             }    
  611.             h += (maxTabHeight - overlay);            
  612.         }
  613.     }
  614.  
  615.     protected int getRunIndent(int run) {
  616.         // Indent beyond where the previous border ended, plus some slop
  617.         return (getTopSegmentIndent() + tabBorderSize[TAB_TOP_SEGMENT] + ROW_INDENT_SLOP) * run + ROW_INDENT_SLOP;
  618.     }
  619.  
  620.     protected void padRun(int start, int end, int maxX) {}
  621.     protected void padSelectedTab(JTabbedPane pane) {}
  622.  
  623.  
  624.     protected int tabWidth(JTabbedPane pane, int index, FontMetrics metrics) {
  625.         int hIndent = getTopSegmentIndent();
  626.  
  627.         String title = pane.getTitleAt(index);
  628.         Icon icon = pane.getIconAt(index);
  629.  
  630.         int width = 2 * hIndent;
  631.  
  632.         if (icon != null)
  633.             width += icon.getIconWidth() + iconSpacingWidth;
  634.  
  635.         width += metrics.stringWidth(title);
  636.         return width;
  637.     }
  638.  
  639.     protected Insets getContentBorderInsets(JTabbedPane pane) {
  640.         return contentBorderInsets;
  641.     }
  642.  
  643.     protected int maxTabHeight(JTabbedPane pane) {
  644.         int count = pane.getTabCount();
  645.         Font font = pane.getFont();
  646.         FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(font);
  647.         int height = metrics.getHeight();
  648.  
  649.         while (count-- > 0) {
  650.             Icon icon = pane.getIconAt(count);
  651.  
  652.             if (icon != null) {
  653.                 int iconHeight = icon.getIconHeight();
  654.  
  655.                 if (iconHeight > height) {
  656.                     height = iconHeight;
  657.                 }
  658.             }
  659.         }
  660.         
  661.         // adjust size to contain a whole number of MIDDLE SEGMENTS
  662.         int rem = height % tabBorderSize[TAB_MIDDLE_SEGMENT];
  663.         if (rem > 0)
  664.             height += (tabBorderSize[TAB_MIDDLE_SEGMENT] - rem);
  665.  
  666.         // Calculate number of MID SEGMENTS
  667.         numMidSegments = (height / tabBorderSize[TAB_MIDDLE_SEGMENT]) - 1 /* allow for the BOTTOM SEGMENT */;
  668.  
  669.         maxTabHeight = tabBorderSize[TAB_TOP_SEGMENT] + (numMidSegments * tabBorderSize[TAB_MIDDLE_SEGMENT]) + tabBorderSize[TAB_BOTTOM_SEGMENT];
  670. //        maxTabHeight = height + TOP_BORDER_HEIGHT + (tabBorderSize[TAB_BOTTOM_SEGMENT] - tabBorderSize[TAB_MIDDLE_SEGMENT]);
  671.         return maxTabHeight;
  672.     }
  673.     
  674.     public int tabForCoordinate(JTabbedPane pane, int x, int y) {
  675.         int theTab = super.tabForCoordinate(pane, x, y);
  676.         
  677.         // If the coordinate is in a tab rectangle, see if it is 
  678.         //    within the 'real' area of the tab.
  679.         if (theTab >= 0)
  680.         {
  681.             int relativeX = x - rects[theTab].x;
  682.             int relativeY = y - rects[theTab].y;
  683.             int topIndent = getTopSegmentIndent();
  684.  
  685.             //    If the coordinate is in the right tapered area of the tab,
  686.             //    Normalize it to the left for simplicity.
  687.             if (relativeX > (rects[theTab].width - topIndent))
  688.             {
  689.                 relativeX = rects[theTab].width - relativeX;
  690.             }
  691.             // If the coordinate is not in the left tapered area of the tab,
  692.             //    it is a valid tab coordinate
  693.             else if (relativeX > topIndent)
  694.             {
  695.                 return theTab;
  696.             }
  697.  
  698.             //    The coordinate is in the tapered area of the tab.
  699.             //    Need to do more work to determine if it is a valid tab coordinate
  700.  
  701.             if (relativeY <= tabBorderSize[TAB_TOP_SEGMENT])
  702.             {
  703.                 if (relativeX <= (topIndent - tabBorderSize[TAB_TOP_SEGMENT]))
  704.                     theTab = -1;        // Top segment region is complicated.  Assume it fails.
  705.             }
  706.             else if (relativeY < maxTabHeight - tabBorderSize[TAB_BOTTOM_SEGMENT])
  707.             {
  708.                 // Must be in the Mid sections.  Determine which one.
  709.                 int theMidSection = (relativeY - tabBorderSize[TAB_TOP_SEGMENT]) / tabBorderSize[TAB_MIDDLE_SEGMENT];
  710.                 
  711.                 if (relativeX <= (theMidSection + tabBorderX[TAB_MIDDLE_SEGMENT][TAB_LEFT_SIDE]))
  712.                     theTab = -1;
  713.             }
  714.             else
  715.             {
  716.                 // Bottom segment region is complicated.  Assume it succeeds
  717.             }
  718.         }
  719.         
  720.         return theTab;
  721.     }
  722.  
  723.     private void repaintTab(JTabbedPane pane, int tab) {
  724.         pane.repaint(rects[tab]);
  725.     }
  726.     private int getTopSegmentIndent() {
  727.         return tabBorderX[TAB_TOP_SEGMENT][TAB_LEFT_SIDE] + numMidSegments - 1;
  728.     }
  729.  
  730.     class MacTabbedPaneMouseGetter implements MouseListener, MouseMotionListener, Serializable {
  731.         int mousePressedTab = -1;
  732.  
  733.  
  734.             //
  735.             // MouseListener methods
  736.             //
  737.         /**
  738.          * Invoked when a mouse button has been pressed on a component.
  739.          */
  740.         public void mousePressed(MouseEvent e) {
  741.             mouseHiliteTab = -1;
  742.  
  743.             JTabbedPane pane = (JTabbedPane) e.getSource();
  744.             mousePressedTab = tabForCoordinate(pane, e.getX(), e.getY());
  745.  
  746.             if (mousePressedTab == pane.getSelectedIndex())
  747.             {
  748.                 mousePressedTab = -1;
  749.             }
  750.             else if (mousePressedTab >= 0)
  751.             {
  752.                 if (tabColor[PRESSED][TAB_BACKGROUND] == null)
  753.                     initPressedTabColors();
  754.                 mouseHiliteTab = mousePressedTab;
  755.  
  756.                 repaintTab(pane, mouseHiliteTab);
  757.             }
  758.         }
  759.     
  760.         /**
  761.          * Invoked when a mouse button has been released on a component.
  762.          */
  763.         public void mouseReleased(MouseEvent e) {
  764.             mouseHiliteTab = -1;
  765.  
  766.             if (mousePressedTab >= 0)
  767.             {
  768.                 JTabbedPane pane = (JTabbedPane) e.getSource();
  769.                 if (mousePressedTab == tabForCoordinate(pane, e.getX(), e.getY()))
  770.                 {
  771.                     pane.setSelectedIndex(mousePressedTab);
  772.                 }
  773.             }
  774.         }
  775.     
  776.     
  777.         /**
  778.          * Ignored
  779.          */
  780.         public void mouseClicked(MouseEvent e) {}
  781.         /**
  782.          * Ignored
  783.          */
  784.         public void mouseEntered(MouseEvent e) {}
  785.         /**
  786.          * Ignored
  787.          */
  788.         public void mouseExited(MouseEvent e) {}
  789.     
  790.     
  791.             //
  792.             // MouseMotionListener methods
  793.             //
  794.     
  795.         /**
  796.          * Invoked when a mouse button is pressed on a component and then 
  797.          * dragged.  Mouse drag events will continue to be delivered to
  798.          * the component where the first originated until the mouse button is
  799.          * released (regardless of whether the mouse position is within the
  800.          * bounds of the component).
  801.          */
  802.         public void mouseDragged(MouseEvent e) {
  803.             if (mousePressedTab >= 0)
  804.             {
  805.                 JTabbedPane pane = (JTabbedPane) e.getSource();
  806.  
  807.                 int newMouseHiliteTab;
  808.                 if (mousePressedTab == tabForCoordinate(pane, e.getX(), e.getY()))
  809.                     newMouseHiliteTab = mousePressedTab;
  810.                 else
  811.                     newMouseHiliteTab = -1;
  812.                 
  813.                 if (mouseHiliteTab != newMouseHiliteTab)
  814.                 {
  815.                     if (mouseHiliteTab != -1)
  816.                         repaintTab(pane, mouseHiliteTab);
  817.  
  818.                     mouseHiliteTab = newMouseHiliteTab;
  819.  
  820.                     if (mouseHiliteTab != -1)
  821.                         repaintTab(pane, mouseHiliteTab);
  822.                 }
  823.             }
  824.         }
  825.  
  826.         /**
  827.          * Ignored
  828.          */
  829.         public void mouseMoved(MouseEvent e) {}
  830.     }
  831. }
  832.